package com.dsteiner.xelavos.client.controller;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Date;
import java.util.List;

import com.dsteiner.widgets.client.IJsUtil;
import com.dsteiner.widgets.client.JsUtil;
import com.dsteiner.widgets.client.Widgets.IButton;
import com.dsteiner.widgets.client.Widgets.IFlowPanel;
import com.dsteiner.widgets.client.Widgets.IHTML;
import com.dsteiner.widgets.client.Widgets.ILazyWidget;
import com.dsteiner.widgets.client.Widgets.IWidget;
import com.dsteiner.widgets.client.Widgets.IWidgetBuilder;
import com.dsteiner.widgets.client.Widgets.WidgetListenerAdapter;
import com.dsteiner.widgets.client.domain.ModelObject;
import com.dsteiner.widgets.client.domain.SearchableRefId;
import com.dsteiner.widgets.client.domain.Sort;
import com.dsteiner.widgets.client.event.DataUpdateEvent;
import com.dsteiner.widgets.client.event.EventManagerImpl;
import com.dsteiner.widgets.client.event.MessageEvent;
import com.dsteiner.widgets.client.model.PaginationModel;
import com.dsteiner.widgets.client.model.PopupOverlayModel;
import com.dsteiner.widgets.client.model.PrefilledTextBoxModel;
import com.dsteiner.widgets.client.rpc.CrudResult;
import com.dsteiner.widgets.client.rpc.SearchResult;
import com.dsteiner.widgets.client.rpc.SearchRequest.SearchRequestImpl;
import com.dsteiner.xelavos.client.constants.Constants;
import com.dsteiner.xelavos.client.domain.Comment;
import com.dsteiner.xelavos.client.domain.Commentable;
import com.dsteiner.xelavos.client.domain.User;
import com.dsteiner.xelavos.client.model.AuthenticationModel;
import com.dsteiner.xelavos.client.model.CommentModel;
import com.dsteiner.xelavos.client.model.CommentsModel;
import com.dsteiner.xelavos.client.rpc.DataService;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class CommentsController {

	private CommentsModel commentsModel;
	private PrefilledTextBoxModel messageTextBoxModel;
	private IFlowPanel contentPanel;
	private IWidgetBuilder widgetBuilder;
	private AuthenticationModel authenticationModel;
	private PaginationModel paginationModel;
	private PopupOverlayModel popupOverlayModel;
	private IJsUtil jsUtil;

	public void registerAuthenticationModel(AuthenticationModel authenticationModel) {
		this.authenticationModel = authenticationModel;
	}

	public void registerCommentsModel(CommentsModel commentsModel) {
		this.commentsModel = commentsModel;
		commentsModel.addPropertyChangeListener("comments", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateComments();
			}
		});
		commentsModel.addPropertyChangeListener("refObject", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				loadComments();
				updatePaginationCount();
			}
		});
	}

	public void registerCommentsWidget(ILazyWidget commentsWidget) {
		commentsWidget.addWidgetListener(new WidgetListenerAdapter() {
			@Override
			public void onAttach(IWidget widget) {
				loadComments();
				updateComments();
				updatePaginationCount();
			}
		});
	}

	public void registerContentPanel(IFlowPanel contentPanel) {
		this.contentPanel = contentPanel;
	}

	public void registerIWidgetBuilder(IWidgetBuilder widgetBuilder) {
		this.widgetBuilder = widgetBuilder;
	}

	public void registerMessageTextBoxModel(PrefilledTextBoxModel messageTextBoxModel) {
		this.messageTextBoxModel = messageTextBoxModel;
	}

	public void registerPaginationModel(PaginationModel paginationModel) {
		this.paginationModel = paginationModel;
		paginationModel.addPropertyChangeListener("page", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				loadComments();
			}
		});
		paginationModel.addPropertyChangeListener("itemsPerPage", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				loadComments();
			}
		});
	}

	public void registerSendButton(final IButton sendButton) {
		sendButton.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				User user = authenticationModel.getUser();
				jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_CLICKED_ADD_BUTTON);
				if(user == null){
					jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_MSG_SHOWN, Constants.LBL_NOT_LOGGED_IN);
					JsUtil.getInstance().showAlert("necesita estar logeado para hacer comentarios");
					return;
				}
				
				if(!messageTextBoxModel.isEdited()){
					jsUtil.trackEvent(Constants.CAT_COMMENT, Constants.ACT_MSG_SHOWN, Constants.LBL_NO_COMMENT_ENTERED);
					JsUtil.getInstance().showAlert("escriba un comentario");
					return;
				}
				
				Comment comment = new Comment();
				comment.setMessage(messageTextBoxModel.getText());
				comment.setRegisteredDate(new Date());
				comment.setUserId(user.getId());
				comment.setUserFirstName(user.getFirstName());
				ModelObject refObject = commentsModel.getRefObject();
				comment.setRefId(refObject.getId());
				comment.setRefClass(refObject.getClass().getName());
				sendButton.setEnabled(false);
				EventManagerImpl.getInstance().fireEvent(new MessageEvent("agregar comentario...", MessageEvent.TYPE_ACTIVITY));
				
				DataService.Util.getInstance().createModelObject(comment, new AsyncCallback<CrudResult<ModelObject>>(){
					public void onFailure(Throwable caught) {
						EventManagerImpl.getInstance().fireEvent(new MessageEvent("agregar comentario falló", MessageEvent.TYPE_ALERT));
						caught.printStackTrace();
						sendButton.setEnabled(true);
					}
					public void onSuccess(CrudResult result) {
						sendButton.setEnabled(true);
						String errorMsg = result.getError();
						if(errorMsg != null){
							EventManagerImpl.getInstance().fireEvent(new MessageEvent(errorMsg));
						}else{
							EventManagerImpl.getInstance().fireEvent(new MessageEvent("comentario agregado", MessageEvent.TYPE_INFO));
							commentsModel.addComment((Comment) result.getModelObject());
							messageTextBoxModel.setText(null);
							
							Commentable commentable = (Commentable) commentsModel.getRefObject();
							commentable.addCommentCount(1);
							EventManagerImpl.getInstance().fireEvent(new DataUpdateEvent(commentable));
							
							updatePaginationCount();
						}
					}
				});
			}
		});
	}

	private void loadComments() {
		ModelObject refObject = commentsModel.getRefObject();
		if(refObject == null)
			return;
		if(((Commentable)refObject).getCommentCount() == 0)
			return;
		
		EventManagerImpl.getInstance().fireEvent(new MessageEvent("cargando comentarios...", MessageEvent.TYPE_ACTIVITY));
		int offset = paginationModel.getOffset();
		int limit = paginationModel.getItemsPerPage();
		SearchRequestImpl searchRequest = new SearchRequestImpl(refObject.getId(), Comment.class.getName(), 
				new Sort("registeredDate", false), offset, limit);
		searchRequest.setAnnotationClassName(SearchableRefId.class.getName());
		DataService.Util.getInstance().search(searchRequest, new AsyncCallback<SearchResult<Comment>>(){
			public void onFailure(Throwable caught) {
				EventManagerImpl.getInstance().fireEvent(new MessageEvent("cargar comentarios fallo", MessageEvent.TYPE_ALERT));
				caught.printStackTrace();
			}

			public void onSuccess(SearchResult<Comment> result) {
				EventManagerImpl.getInstance().fireEvent(new MessageEvent(null, MessageEvent.TYPE_INFO));
				commentsModel.setComments(result.getObjects());
			}
			
		});
	}

	private void updateComments() {
		contentPanel.clear();
		List<Comment> comments = commentsModel.getComments();
		if(comments == null)
			return;
		
		for (Comment comment : comments) {
			CommentModel commentModel = new CommentModel();
			commentModel.setModelObject(comment);
			IWidget widget = widgetBuilder.createWidget(commentModel);
			contentPanel.add(widget);
		}
		
	}

	private void updatePaginationCount() {
		Commentable refObject = (Commentable) commentsModel.getRefObject();
		if(refObject == null)
			return;
		paginationModel.setCount(refObject.getCommentCount());
	}

	public void registerJsUtil(IJsUtil jsUtil) {
		this.jsUtil = jsUtil;
	}
}